package roslan.musicbox.client.data;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;

import javax.swing.ImageIcon;

import org.farng.mp3.MP3File;
import org.farng.mp3.id3.AbstractID3v2;
import org.farng.mp3.id3.AbstractID3v2Frame;
import org.farng.mp3.id3.ID3v1;
import org.farng.mp3.id3.ID3v2_2;
import org.farng.mp3.id3.ID3v2_3;
import org.farng.mp3.id3.ID3v2_4;

import roslan.musicbox.utils.StringEncodingTool;
import roslan.musicbox.utils.UIComponentUtils;

public class MusicFile {
	private MP3File musicFile;
	private File stdFile;
	private boolean isMusicFile;
	
	private ClientMusicTag musicTag;
	
	public void setMusicTag(ClientMusicTag tag){
		this.musicTag = tag;
	}
	
	public ClientMusicTag getMusicTag(){
		return this.musicTag;
	}
	
	public MusicFile(String path){
		stdFile = new File(path);
		try {
			musicFile = new MP3File(path);
		} catch (Exception e){
			isMusicFile = false;
			return;
		}
		isMusicFile = true;
		musicTag = new ClientMusicTag();
		extractTagInfo();
	}
	
	public MusicFile(File file){
		stdFile = file;
		try {
			musicFile = new MP3File(file);
		} catch (Exception e){
			isMusicFile = false;
			return;
		}
		isMusicFile = true;
		musicTag = new ClientMusicTag();
		extractTagInfo();
	}
	
	public boolean isMusicFile(){
		return isMusicFile;
	}
	
	public void extractTagInfo(){
		if(musicFile.hasID3v2Tag()){
			try{
				extractTagV2();
			}catch(UnsupportedEncodingException ufe){
				musicTag.setUnknown();
			}
		}else if(musicFile.hasID3v1Tag()){
			try{
				extractTagV1();
			}catch(UnsupportedEncodingException ufe){
				musicTag.setUnknown();
			}
		}else{
			musicTag.setUnknown();
		}
		musicTag.setApic(extractApic());
	}

	
	public String getPath(){
		if(!isMusicFile) return null;
		return stdFile.getAbsolutePath();
	}
	
	public String getName(){
		if(!isMusicFile) return null;
		return stdFile.getName();
	}
	
	public MP3File getMusicFile(){
		if(!isMusicFile) return null;
		return musicFile;
	}
	
	public File getStdFile(){
		if(!isMusicFile) return null;
		return stdFile;
	}
	
	public boolean exists(){
		if(!isMusicFile) return false;
		return stdFile.exists();
	}
	
	private void extractTagV1() 
	throws UnsupportedEncodingException{
		ID3v1 tagV1 = musicFile.getID3v1Tag();
		musicTag.setTagVersion("v1");

		String album  = StringEncodingTool.encode(
				tagV1.getAlbumTitle(), "ISO8859-1", "gb2312");
		String artist = StringEncodingTool.encode(
				tagV1.getLeadArtist(), "ISO8859-1", "gb2312");
		String title  = StringEncodingTool.encode(
				tagV1.getSongTitle(), "ISO8859-1", "gb2312");
		String year   = StringEncodingTool.encode(
				tagV1.getYearReleased(), "ISO8859-1", "gb2312");
		String genre  = StringEncodingTool.encode(
				tagV1.getSongGenre(), "ISO8859-1", "gb2312");
		String comment= StringEncodingTool.encode(
				tagV1.getSongComment(), "ISO8859-1", "gb2312");
		String trackNumber = ClientMusicTag.UNKNOWN;
		
		musicTag.setAlbum(album);
		musicTag.setArtist(artist);
		musicTag.setTitle(title);
		musicTag.setYear(year);
		musicTag.setGenre(genre);
		musicTag.setComment(comment);
		musicTag.setTrackNumber(trackNumber);
				
	}
	
	private void extractTagV2() throws UnsupportedEncodingException {
		byte b = musicFile.getID3v2Tag().getMajorVersion();
		AbstractID3v2 tagV2 = null;
		if(b==2){
			tagV2 = (ID3v2_2)musicFile.getID3v2Tag();
			musicTag.setTagVersion("v2.2");
		}else if(b==3){
			tagV2 = (ID3v2_3)musicFile.getID3v2Tag();
			musicTag.setTagVersion("v2.3");
		}else if(b==4){
			tagV2 = (ID3v2_4)musicFile.getID3v2Tag();
			musicTag.setTagVersion("v2.4");
		}
		String album  = StringEncodingTool.encode(
				tagV2.getAlbumTitle(), "gb2312","gb2312");
		String artist = StringEncodingTool.encode(
				tagV2.getLeadArtist(), "gb2312","gb2312");
		String title  = StringEncodingTool.encode(
				tagV2.getSongTitle(), "gb2312","gb2312");
		String year   = StringEncodingTool.encode(
				tagV2.getYearReleased(), "gb2312","gb2312");
		String genre  = StringEncodingTool.encode(
				tagV2.getSongGenre(), "gb2312","gb2312");
		String comment= StringEncodingTool.encode(
				tagV2.getSongComment(), "gb2312","gb2312");
		String trackNumber = StringEncodingTool.encode(
				tagV2.getTrackNumberOnAlbum(), "gb2312", "gb2312");
		
		musicTag.setAlbum(album);
		musicTag.setArtist(artist);
		musicTag.setTitle(title);
		musicTag.setYear(year);
		musicTag.setGenre(genre);
		musicTag.setComment(comment);
		musicTag.setTrackNumber(trackNumber);
	}
	
	@SuppressWarnings("unchecked")
	private ImageIcon extractApic(){
		if(!isMusicFile) return ClientMusicTag.defaultPic;
		AbstractID3v2 tag = musicFile.getID3v2Tag();
		if(tag==null){
			return ClientMusicTag.defaultPic;
		}
		Iterator iter = tag.getFrameOfType("APIC");
		if(!iter.hasNext()){
			return ClientMusicTag.defaultPic;
		}
		AbstractID3v2Frame frame = (AbstractID3v2Frame)iter.next();
		byte[] data = (byte[])(frame.getBody().getObject("Picture Data"));
		int pos = 0;
		while(pos < data.length - 1 && 
			  (data[pos] != (byte)0xFF || data[pos+1] != (byte)0xD8))
			++pos;
		if(pos>=data.length-2){
			return ClientMusicTag.defaultPic;
		}
		byte[] modifiedData = new byte[data.length-pos];
		for(int i=0;i<modifiedData.length;++i){
			modifiedData[i] = data[i+pos];
		}
		ImageIcon pic = new ImageIcon(modifiedData);
		pic = UIComponentUtils.scaleImageIcon(pic, 
				ClientMusicTag.PIC_SIZE, 
				ClientMusicTag.PIC_SIZE);
		return pic;
	}
}
